﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ExchangeCurrencyRate.Entity;
using System.IO;
using System.Text.RegularExpressions;
using System.Globalization;
using System.Configuration;

namespace ExchangeCurrencyRate.Providers
{
    /// <summary>
    /// This class provides access to currency rates file storage and implements all necessary functionality.
    /// </summary>
    public class CurrencyRateFileProvider : CurrencyRateProvider
    {
        const string DATE_FORMAT = "yyyyMMdd";
        const string FILE_START = "Currency.Rate.";
        const string FILE_END = ".txt";

        public CurrencyRateFileProvider()
        {
        }

        /// <summary>
        /// Get exchange rate from specific file(s).
        /// </summary>
        /// <param name="fromCurrencyCode">First currency</param>
        /// <param name="toCurrencyCode">Second currency</param>
        /// <param name="dateTime">Date</param>
        /// <returns>Returns ExchangeRate from file</returns>
        public override ExchangeRate GetExchangeRate(string fromCurrencyCode, string toCurrencyCode, DateTime dateTime)
        {
            string[] currencyRateFiles = Directory.GetFiles(GetDirectory(), "Currency.Rate.*.txt");
            var validFiles = currencyRateFiles
                .Where(x => GetDateFromFileName(x).Date.CompareTo(dateTime.Date) <= 0)
                .OrderBy(x => x)
                .ToList();
            Regex reg = new Regex(@"^\s*" + fromCurrencyCode + @"\s*\|\s*" + toCurrencyCode + @"\s*\|\s*(?<summ>.+)$", RegexOptions.IgnoreCase | RegexOptions.Singleline);
            foreach (var file in validFiles)
            {
                if (string.IsNullOrEmpty(file) || !File.Exists(file))
                {
                    continue;
                }
                DateTime fileDateTime = GetDateFromFileName(file);
                using (StreamReader reader = File.OpenText(file))
                {
                    while (!reader.EndOfStream)
                    {
                        string line = reader.ReadLine();
                        Match match = reg.Match(line);
                        decimal rate;
                        if (match.Success && decimal.TryParse(match.Groups["summ"].Value.Trim(), out rate))
                        {
                            return new ExchangeRate()
                                {
                                    CurrencyFrom = fromCurrencyCode,
                                    CurrencyTo = toCurrencyCode,
                                    Date = fileDateTime,
                                    Rate = rate,
                                };
                        }
                    }
                }
            }
            return null;
        }

        private string GetDirectory()
        {
            return Path.GetDirectoryName(ConfigurationManager.AppSettings["currencyFilePath"]);
        }

        private string GetFileName(DateTime dateTime)
        {
            return string.Format(FILE_START + "{0:" + DATE_FORMAT + "}" + FILE_END, dateTime);
        }
        /// <summary>
        /// Get date from file name
        /// </summary>
        /// <param name="filePath">Path to file</param>
        /// <returns>Return DateTime</returns>
        private DateTime GetDateFromFileName(string filePath)
        {
            try
            {
                return DateTime.ParseExact(new FileInfo(filePath).Name.Replace(FILE_START, "").Replace(FILE_END, ""), DATE_FORMAT, CultureInfo.CurrentCulture);
            }
            catch (Exception)
            {
                return DateTime.MaxValue;
            }
        }
        /// <summary>
        /// Save Exchange Rate to file
        /// </summary>
        /// <param name="fromCurrencyCode">First currency code</param>
        /// <param name="toCurrencyCode">Second currency code</param>
        /// <param name="dateTime">DateTime</param>
        /// <param name="exchangeRate">Exchange rate</param>
        /// <returns>Returns status</returns>
        public override bool SaveExchangeRate(string fromCurrencyCode, string toCurrencyCode, DateTime dateTime, decimal exchangeRate)
        {
            try
            {
                FileInfo file = new FileInfo(Path.Combine(GetDirectory(), GetFileName(dateTime)));
                Regex reg = new Regex(@"^\s*(?<curr1>\w+)\s*\|\s*(?<curr2>\w+)\s*\|\s*(?<summ>.+)$", RegexOptions.IgnoreCase | RegexOptions.Singleline);
                List<ExchangeRate> exchangeRateList = new List<ExchangeRate>();
                if (file.Exists)
                {
                    using (StreamReader reader = file.OpenText())
                    {
                        while (!reader.EndOfStream)
                        {
                            string line = reader.ReadLine();
                            Match match = reg.Match(line);
                            decimal rate;
                            if (match.Success && decimal.TryParse(match.Groups["summ"].Value.Trim(), out rate))
                            {
                                exchangeRateList.Add(new ExchangeRate()
                                    {
                                        CurrencyFrom = match.Groups["curr1"].Value.Trim(),
                                        CurrencyTo = match.Groups["curr2"].Value.Trim(),
                                        Date = dateTime,
                                        Rate = rate,
                                    });
                            }
                        }
                    }
                }
                var exchangeRateObj = exchangeRateList.Where(x => x.CurrencyFrom.Equals(fromCurrencyCode) && x.CurrencyTo.Equals(toCurrencyCode)).FirstOrDefault();
                if (null == exchangeRateObj)
                {
                    exchangeRateList.Add(new ExchangeRate()
                    {
                        CurrencyFrom = fromCurrencyCode.Trim(),
                        CurrencyTo = toCurrencyCode.Trim(),
                        Date = dateTime,
                        Rate = exchangeRate,
                    });
                }
                else
                {
                    exchangeRateObj.Date = dateTime;
                    exchangeRateObj.Rate = exchangeRate;
                }
                using (StreamWriter writer = file.CreateText())
                {
                    foreach (var item in exchangeRateList)
                    {
                        writer.WriteLine(string.Format("{0}|{1}|{2}", item.CurrencyFrom, item.CurrencyTo, item.Rate));
                    }
                }
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }
    }
}
